// X86Translator.h
// Defines the class X86Translator
#ifndef X86TRANSLATOR_H
#define X86TRANSLATOR_H

#include "crossbit/common.h"
#include "crossbit/Translator.h"
#include "crossbit/RegAllocator.h"
#include "arch/ia32/IA32ProcessorState.h"
#include <map>
#include <set>
#include <deque>
#include <vector>

namespace crossbit {

    class TBlock;
    class VInst;

    class X86Translator : public Translator {
        public:
            const static int CACHE_SIZE = 1024;

            X86Translator(IA32ProcessorState *state, RegAllocator *alloc);
            ~X86Translator();

            // maybe don't need this function now
            // TBlock * headBlock();

            void setRegAllocator(RegAllocator * allocator)
            {
                reg_allocator = allocator;
            }

            void encode(VBlock *vb, TBlock *tb);

#if 0
            void setContextReturn(void *ret) 
            {
                GLOBAL::return_address = (XTMemAddr)ret;
            }
#endif

            inline void setFirstTime()
            {
                this->first_time = true;
            }


            static struct RegisterFile {
                XTInt32 eax;
                XTInt32 ecx;
                XTInt32 edx;
                XTInt32 ebx;
                XTInt32 ebp;
                XTInt32 esp;
                XTInt32 esi;
                XTInt32 edi;
            } saved;

        private:
            void initTranslation();
            IA32ProcessorState *src_state;
            VBlock *vblock;
            TBlock *tblock;

            bool first_time;
            bool dirty_esp;
            XTInt32 saved_esp;

            // the Translator should hold a pointer of reg allocator
            RegAllocator* reg_allocator;


            // =========================================================
            // Wrapper functions of reg allocator, since allocator may 
            // use ESP, and the X86Translator should deal with it.
            XTRegNum X86RegAlloc(XTRegNum vreg, RegAccessMode mode);
            XTRegNum X86RegAllocForce(XTRegNum vreg, XTRegNum expect, RegAccessMode mode);
            XTRegNum X86RegAllocForceExcept(XTRegNum vreg, XTRegNum except, RegAccessMode mode);
            void X86RegAllocReserve(XTRegNum treg);
            void X86RegAllocRelease(XTRegNum treg);


            // =========================================================
            //	    Exits Related

            void setBlockStub();	//for trace linking, added by zhengjuyu

            void endOfBlock();
            inline XTInt32 addTBlockExit(XTInt32 why, XTMemAddr next, XTInt32 exitOffset, VInst *inst);
            void encodeExits();


            // =========================================================
            //	    Encoding Related

            XTMemAddr inst_buf;	// instruction buffer
            XTMemAddr p_inst_buf;	// pointer to instruction buffer
            VInst *inst;	// current to-be-encoded virtual instruction

            // the loopAddr and labelAddr are used for Loop instruction
            XTMemAddr loopAddr[2];
            XTMemAddr labelAddr[2];

            void encodeGET();
            void encodePUT();
            void encodeLD();
            void encodeST();
            void encodeLI();
            void encodeMOV();
            void encodeSEXT();
            void encodeZEXT();
            void encodeADD();
            void encodeSUB();
            void encodeADDI();
            void encodeSUBI();
            void encodeAND();
            void encodeXOR();
            void encodeOR();
            void encodeNOT();
            void encodeMUL();
            void encodeMULU();
            void encodeDIV();
            void encodeDIVU();
            void encodeSLL();
            void encodeSLLV();
            void encodeSRL();
            void encodeSRLV();
            void encodeSRA();
            void encodeSRAV();
            void encodeCMP();
            void encodeJMP();
            void encodeBRANCH();
            void encodeSYSCALL();
            void encodeSBREAK();

            /*
             * The following are newly introduced VInsts in ia32 front end.
             */
            void encodeUSE();
            void encodeBSF();
            void encodeBSR();
            void encodeDIVU64();
            // LOOP and LABEL
            void encodeLOOP();
            void encodeLOOPN();
            void encodeLABEL();


            void encodeFPUTS();
            void encodeFGETS();
            void encodeFPUTD();
            void encodeFGETD();

            void encodeFLD();
            void encodeFST();
            void encodeFMOV();

            void encodeFADDS();
            void encodeFADDD();
            void encodeFSUBS();
            void encodeFSUBD();
            void encodeFMULS();
            void encodeFMULD();
            void encodeFDIVS();
            void encodeFDIVD();
            void encodeFNEGS();
            void encodeFNEGD();
            void encodeFABSS();
            void encodeFABSD();
            void encodeFSQRTS();
            void encodeFSQRTD();
            void encodeFCMPS();
            void encodeFCMPD();

            void encodeCONV();
            void encodeFINCSTP();
            void encodeCALL();


            /*
             * The following are newly introduced float VInsts in ia32 front end.
             */
            void encodeFYL2X();
            void encodeFYL2XP1();
            void encodeFLDL2E();
            void encodeFLDLG2();
            void encodeFLDLN2();
            void encodeFCOS();
            void encodeFPTAN();
            void encodeFSIN();
            void encodeFCHS();
            void encodeFSCALE();
            void encodeF2XM1();
            void encodeFXAM();
            void encodeFRNDINT();

            XTInt32 *allocFpWord(XTInt32);
            XTInt64 *allocFpDword(XTInt64);

            XTInt32 call_stack[CACHE_SIZE];  // 1k words
            XTInt32 fp_word_cache[CACHE_SIZE];
            XTInt64 fp_dword_cache[CACHE_SIZE];
            XTInt32 fp_word_count;
            XTInt32 fp_dword_count;

            // Variables for encoding LOOP, LABEL pairs
            /*
               Word labelAddr[2];
               Word loopAddr[2];
               */
    };
}

#endif
